use actix_web::{get, post, web::{self, Query, ServiceConfig}};
use serde::Deserialize;
use super::IdReq;
use crate::{error::AppErr, store::product::{self, Product}, web::{codec::{cbor::{new_ok_cbor, Cbor, CborRet}, device_session::notify_product_update, session::Session, user_session::UserSession, Void}, download::{new_download, Download}}};

#[derive(Debug, Deserialize)]
struct CreateReq {
    name: String,
    price: u32,
    #[serde(with = "serde_bytes")]
    image: Box<[u8]>,
}

#[post("/create")]
async fn on_create(_: UserSession, req: Cbor<CreateReq>) -> CborRet<i64> {
    let id = product::create(&req.name, req.price, &req.image).await?;
    notify_product_update().await?;
    new_ok_cbor(id)
}

#[get("/query")]
async fn on_query(_: Session) -> CborRet<Box<[product::Product]>> {
    new_ok_cbor( product::query().await? )
}

#[post("/edit")]
async fn on_edit(_: UserSession, product: Cbor<Product>) -> Result<Void, AppErr> {
    product::edit(&product).await?;
    notify_product_update().await?;
    Ok(Void)
}

#[get("/query_no_image")]
async fn on_query_no_image(_: Session) -> CborRet<Box<[product::ProductNoImage]>> {
    new_ok_cbor( product::query_no_image().await? )
}

#[get("/down_image")]
async fn on_down_image(id: Query<IdReq>) -> Result<Download, AppErr> {
    let body = product::get_image(id.id).await?;
    Ok(new_download(format!("image_{}", id.id), body))
}

#[derive(Debug, Deserialize)]
struct DeviceIdReq {
    device_id: i64
}

#[get("/query_by_device")]
async fn on_query_by_device(req: Query<DeviceIdReq>) -> CborRet<Box<[product::Product]>> {
    new_ok_cbor( product::query_by_device_id(req.device_id).await? )
}

pub fn register(cfg: &mut ServiceConfig) {
    let scope = web::scope("/product")
        .service(on_create)
        .service(on_query)
        .service(on_query_by_device)
        .service(on_edit)
        .service(on_query_no_image)
        .service(on_down_image)
        ;
    cfg.service(scope);
}
